package com.yyks.es.dubbo.service.hotel;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.common.appcommon.json.JsonImageRoom;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.constants.cnbooking.EsCnPrice;
import com.yeyks.common.utils.CommonRandomUtils;
import com.yeyks.common.utils.DateUtils;
import com.yeyks.common.utils.JsonUtils;
import com.yeyks.common.utils.apputil.bean.MyBeanUtils;
import com.yeyks.common.utils.apputil.rediskey.BuilderKey;
import com.yeyks.common.utils.apputil.rediskey.RedisKey;
import com.yeyks.commonReference.append.mongodb.entity.CnHotelImageMongoEntity;
import com.yeyks.commonReference.append.mongodb.entity.CnRoomImageMongoEntity;
import com.yeyks.commonReference.append.mongodb.service.CnHotelImageMongoMongoService;
import com.yeyks.commonReference.append.mongodb.service.CnRoomImageMongoMongoService;
import com.yeyks.hotel.dal.dao.HotelBlackListMapper;
import com.yeyks.hotel.dal.dao.HotelInfoMapper;
import com.yeyks.hotel.dal.domain.HotelBlackList;
import com.yeyks.hotel.dal.domain.HotelInfo;
import com.yeyks.other.dal.domain.ImportCityDataConfig;
import com.yeyks.other.service.ImportCityDataConfigService;
import com.yyks.cnbooking.dubbo.dto.calendar.RoomCalendarDTO;
import com.yyks.cnbooking.dubbo.dto.hotel.HotelInfoDTO;
import com.yyks.cnbooking.dubbo.dto.room.RoomInfoDTO;
import com.yyks.cnbooking.dubbo.param.hotel.CbHotelListSearchParam;
import com.yyks.cnbooking.dubbo.result.hotelsearch.CbHotel;
import com.yyks.cnbooking.dubbo.service.TransitionService;
import com.yyks.cnbooking.dubbo.service.redis.RedisService;
import com.yyks.es.dubbo.constants.EsIndexConstant;
import com.yyks.es.dubbo.pojo.model.EsHotelInfo;
import com.yyks.es.dubbo.pojo.model.EsRoomCalendarInfo;
import com.yyks.es.dubbo.pojo.model.EsRoomInfo;
import com.yyks.es.dubbo.pojo.model.base.EsDocType;
import com.yyks.es.dubbo.pojo.model.base.EsGeoPoint;
import com.yyks.es.dubbo.service.ElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.rest.RestStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: dagny
 * @date: 2019/10/9 0009 18:29
 */
@Service
@Slf4j
public class EsImportHotelServiceImpl implements EsImportHotelService {

    @Autowired
    private EsHotelInformationService esHotelInformationService;

    @Autowired
    private ElasticSearchService elasticSearchService;

    @Autowired
    private HotelInfoMapper hotelInfoMapper;

    @Reference
    private TransitionService transitionService;

    @Autowired
    private CnRoomImageMongoMongoService roomImageMongoMongoService;

    @Autowired
    private CnHotelImageMongoMongoService hotelImageMongoMongoService;

    @Autowired
    private HotelBlackListMapper hotelBlackListMapper;

    @Reference
    private RedisService redisService;

    @Autowired
    private ImportCityDataConfigService importCityDataConfigService;

    /**
     * yyks_根据酒店ID 导入酒店数据
     *
     * @param hotelId   酒店ID
     * @param indexName 索引名称
     */
    @Override
    public void importHotelByHotelId(Integer hotelId, String indexName) {
        //先创建索引
        try {
            elasticSearchService.createIndex(indexName);
        } catch (Exception e) {
            log.info("不需要==创建索引");
        }
        //查询所有未删除的酒店；

        EsHotelInfo esHotelInfo = esHotelInformationService.searchHotel(hotelId);
        List<EsRoomInfo> roomInfoList = Lists.newArrayList();
        List<EsRoomCalendarInfo> roomCalendarInfoList;
        if (null != esHotelInfo) {
            roomInfoList.addAll(esHotelInformationService.searchRoomList(hotelId));
            if (!CollectionUtils.isEmpty(roomInfoList)) {
                roomCalendarInfoList = esHotelInformationService.searchRoomCalendarList(roomInfoList);
                if (!CollectionUtils.isEmpty(roomCalendarInfoList)) {
                    //创建酒店数据
                    elasticSearchService.createHotelDocument(JSONUtil.toJsonStr(esHotelInfo), indexName, esHotelInfo.getHotelId());
                    //创建房间数据
                    elasticSearchService.createMoreRoomDocument(roomInfoList, indexName);
                    //创建房态数据
                    elasticSearchService.createMoreRoomCalendarDocument(roomCalendarInfoList, indexName);
                }
            }
        }
    }

    /**
     * yyks_批量 分页导入所有酒店数据
     *
     * @param indexName 索引名称
     */
    @Override
    public void importHotelByPage(String indexName) {

        //先创建索引
        try {
            elasticSearchService.createIndex(indexName);
        } catch (Exception e) {
            log.info("不需要==创建索引");
        }
        long startTime = System.currentTimeMillis();
        List<HotelInfo> hotelInfoList;
        int pageSize = 100;
        int pageNum = 1;
        do {
            int pageNumTmp = pageNum++;
            //查询所有未删除的酒店；
            List<EsHotelInfo> esHotelInfoList;
            List<EsRoomInfo> roomInfoList;
            List<EsRoomCalendarInfo> roomCalendarInfoList;
            PageHelper.startPage(pageNumTmp, pageSize);

            hotelInfoList = hotelInfoMapper.selectList(new QueryWrapper<HotelInfo>().eq(HotelInfo.IS_DEL, 1));
            if (!CollectionUtils.isEmpty(hotelInfoList)) {

                List<Integer> hotelIdList = hotelInfoList.stream().map(HotelInfo::getId).collect(Collectors.toList());

                esHotelInfoList = esHotelInformationService.searchHotelByHotelIdList(hotelIdList);
                roomInfoList = esHotelInformationService.searchRoomListByHotelList(hotelIdList);
                if (!CollectionUtils.isEmpty(roomInfoList)) {
                    roomCalendarInfoList = esHotelInformationService.searchRoomCalendarList(roomInfoList);
                    if (!CollectionUtils.isEmpty(roomCalendarInfoList)) {
                        //创建酒店数据
                        elasticSearchService.createMoreHotelDocument(esHotelInfoList, indexName);
                        //创建房间数据
                        elasticSearchService.createMoreRoomDocument(roomInfoList, indexName);
                        //创建房态数据
                        elasticSearchService.createMoreRoomCalendarDocument(roomCalendarInfoList, indexName);
                    }
                }
                log.info("当前执行第【{}】页数据,酒店ID区间为【{} - {}】完成录入", pageNumTmp, esHotelInfoList.get(0).getId(),
                        esHotelInfoList.get(esHotelInfoList.size() - 1).getId());
            }
        } while (!CollectionUtils.isEmpty(hotelInfoList));

        long endTime = System.currentTimeMillis();

        log.info("录入酒店，房间，房态完成, 消耗总时长【{}】秒", (endTime - startTime) / 1000);

    }

    /**
     * 【yyks_】根据酒店Id集合 酒店数据
     *
     * @param hotelIdList 酒店集合信息
     * @param indexName   索引名称
     */
    @Override
    public void importHotelByHotelIdList(List<String> hotelIdList, String indexName) {

        long startTime = System.currentTimeMillis();
        List<Integer> idList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(hotelIdList)) {
            hotelIdList.forEach(s -> {
                idList.add(Integer.valueOf(s));
            });
        }

        List<EsHotelInfo> esHotelInfoList = esHotelInformationService.searchHotelByHotelIdList(idList);
        if (!CollectionUtils.isEmpty(esHotelInfoList)) {
            elasticSearchService.createMoreHotelDocument(esHotelInfoList, indexName);
        }
        long endTime = System.currentTimeMillis();

        log.info("===更新【酒店】完成，消耗总时长【{}】秒===", (endTime - startTime) / 1000);
    }

    /**
     * 【yyks_】 根据房间Id集合 更新/（录入）【房间，房态】信息
     *
     * @param roomIdList 房间Id集合
     * @param indexName  索引名称
     */
    @Override
    public void importRoomByRoomIdList(List<String> roomIdList, String indexName) {

        long startTime = System.currentTimeMillis();
        List<Integer> idList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(roomIdList)) {
            roomIdList.forEach(s -> {
                idList.add(Integer.valueOf(s));
            });
        }
        List<EsRoomInfo> esRoomInfoList = esHotelInformationService.searchRoomByIds(idList);
        if (!CollectionUtils.isEmpty(esRoomInfoList)) {
            elasticSearchService.createMoreRoomDocument(esRoomInfoList, indexName);

            //更新房态信息
            List<EsRoomCalendarInfo> esRoomCalendarInfos = esHotelInformationService.searchRoomCalendarList(esRoomInfoList);
            if (!CollectionUtils.isEmpty(esRoomCalendarInfos)) {
                //房间更新
                elasticSearchService.createMoreRoomDocument(esRoomInfoList, indexName);
                //房态更新
                elasticSearchService.createMoreRoomCalendarDocument(esRoomCalendarInfos, indexName);
            }
        }
        long endTime = System.currentTimeMillis();

        log.info("===更新【房间, 房态】集合完成，消耗总时长【{}】秒===", (endTime - startTime) / 1000);
    }

    /**
     * 【yyks_】 根据房态Id集合 更新/（录入）房态信息
     *
     * @param calenderIdList 房态Id集合
     * @param indexName      索引名称
     */
    @Override
    public void importCalendarByCalendarIdList(List<String> calenderIdList, String indexName) {

        long startTime = System.currentTimeMillis();
        List<Integer> idList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(calenderIdList)) {
            calenderIdList.forEach(s -> {
                idList.add(Integer.valueOf(s));
            });
        }
        List<EsRoomCalendarInfo> esRoomCalendarInfoList = esHotelInformationService.searchRoomCalendarByIds(idList);
        if (!CollectionUtils.isEmpty(esRoomCalendarInfoList)) {
            elasticSearchService.createMoreRoomCalendarDocument(esRoomCalendarInfoList, indexName);
        }
        long endTime = System.currentTimeMillis();

        log.info("===更新【房态】集合完成，消耗总时长【{}】秒===", (endTime - startTime) / 1000);
    }


    /**
     * cnbooking_ 根据酒店ID 导入酒店数据
     *
     * @param hotelId    酒店ID
     * @param indexName  索引名称
     * @param countryId  国家
     * @param provinceId 省
     * @param cityId     城市
     */
    @Override
    public void importCnBookingHotelByHotelId(Integer hotelId, String indexName, String countryId,
                                              String provinceId, String cityId) {

        //先创建索引
        try {
            elasticSearchService.createIndex(indexName);
        } catch (Exception e) {
            //log.info("不需要==创建索引");
        }
        //查询CnBooking的相关酒店

        List<EsRoomInfo> roomInfoList = Lists.newArrayList();
        CbHotel cbHotel = new CbHotel();
        cbHotel.setCountryId(countryId);
        cbHotel.setCityId(cityId);
        cbHotel.setProvinceId(provinceId);
        cbHotel.setHotelId(String.valueOf(hotelId));
        String cityPercent = this.getCityPercent(provinceId, cityId);
        double lowPercent = EsCnPrice.LOW_PERCENT;
        double highPercent = EsCnPrice.HIGH_PERCENT;
        if (Arguments.strNotNull(cityPercent)) {
            String[] split = cityPercent.split("-");
            lowPercent = Double.parseDouble(split[0].trim());
            highPercent = Double.parseDouble(split[1].trim());
        }
        EsHotelInfo esHotelInfo = this.getHotelByCnBooking(cbHotel);
        if (esHotelInfo != null) {
            esHotelInfo.setProvinceId(cbHotel.getProvinceId());
            esHotelInfo.setCityId(cbHotel.getCityId());
            //存入房间数据
            roomInfoList.addAll(getRoomListByCnBooking(cbHotel, esHotelInfo, lowPercent, highPercent));
            if (!CollectionUtils.isEmpty(roomInfoList)) {
                //存入房态信息
                getRoomCalendarByCnBooking(esHotelInfo, indexName, roomInfoList, cbHotel, lowPercent, highPercent);
            }
        }
    }


    /**
     * cnbooking_ 根据酒店ID 【批量】导入酒店数据
     *
     * @param indexName  索引名称
     * @param countryId  国家
     * @param provinceId 省
     * @param cityId     城市
     * @param pageSize   页大小
     * @param pageNo     当前页
     */
    @Override
    public void importCnBookingHotelByPage(String indexName, String countryId, String provinceId, String cityId,
                                           Integer pageSize, Integer pageNo) {

        long startTime = System.currentTimeMillis();
        //先创建索引
        try {
            elasticSearchService.createIndex(indexName);
        } catch (Exception e) {
            log.info("不需要==创建索引");
        }
        //查询CnBooking的相关酒店

        List<EsRoomInfo> roomInfoList = Lists.newArrayList();
        List<EsHotelInfo> hotelListByCnBooking = null;
        if (null == pageSize) {
            pageSize = 10;
        }
        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                int pageNumTmp = pageNo++;
                CbHotelListSearchParam listSearchParam = new CbHotelListSearchParam();
                listSearchParam.setCityId(cityId);
                listSearchParam.setCountryId(countryId);
                listSearchParam.setProvinceId(provinceId);
                listSearchParam.setPageSize(pageSize);
                listSearchParam.setPageNo(pageNumTmp);
                hotelListByCnBooking = this.getHotelListByCnBooking(listSearchParam);
                if (!CollectionUtils.isEmpty(hotelListByCnBooking)) {
                    for (EsHotelInfo esHotelInfo : hotelListByCnBooking) {
                        esHotelInfo.setProvinceId(provinceId);
                        esHotelInfo.setCityId(cityId);
                        //存入酒店数据
                        CbHotel cbHotel = new CbHotel();
                        cbHotel.setCountryId(countryId);
                        cbHotel.setCityId(cityId);
                        cbHotel.setProvinceId(provinceId);
                        cbHotel.setHotelId(String.valueOf(esHotelInfo.getId()));

                        String cityPercent = this.getCityPercent(provinceId, cityId);
                        double lowPercent = EsCnPrice.LOW_PERCENT;
                        double highPercent = EsCnPrice.HIGH_PERCENT;
                        if (Arguments.strNotNull(cityPercent)) {
                            String[] split = cityPercent.split("-");
                            lowPercent = Double.parseDouble(split[0].trim());
                            highPercent = Double.parseDouble(split[1].trim());
                        }
                        //存入房间数据
                        roomInfoList.addAll(getRoomListByCnBooking(cbHotel, esHotelInfo, lowPercent, highPercent));
                        if (!CollectionUtils.isEmpty(roomInfoList)) {
                            //存入房态信息
                            getRoomCalendarByCnBooking(esHotelInfo, indexName, roomInfoList, cbHotel, lowPercent, highPercent);
                        }
                        //不同的酒店初始化
                        roomInfoList.clear();
                    }
                }
                log.info("===================酒店分页数据导入完成，当前完成录入的页数为【{}】==========================", pageNumTmp);
            } catch (Exception e) {
                e.printStackTrace();
            }

        } while (!CollectionUtils.isEmpty(hotelListByCnBooking));

        long endTime = System.currentTimeMillis();

        log.info("酒店数据录入完成，消耗总时长【{}】毫秒",
                (endTime - startTime));
    }

    /**
     * @param highPercent 销售价上浮百分比 （如） 1.1 表示上涨 10%
     * @param lowPercent  底价下浮百分比 （如） 0.95 表示下浮 5%
     * @param calendarId  房态ID
     */
    @Override
    public void updateCalendarPrice(String indexName, String highPercent, String lowPercent, String calendarId, Integer pageSize,
                                    Integer pageNo) {

        long startTime = System.currentTimeMillis();
        List<EsRoomCalendarInfo> esRoomCalendarInfos = null;

        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                int pageNumTmp = pageNo++;
                esRoomCalendarInfos = elasticSearchService.c2bSearchCalendar(indexName, "cn", calendarId
                        , pageSize, pageNumTmp);
                if (!CollectionUtils.isEmpty(esRoomCalendarInfos)) {

                    esRoomCalendarInfos.forEach(esRoomCalendarInfo -> {

                        //现价,底价动态更新，根据插入的数据更新
                        if (!StringUtils.isEmpty(esRoomCalendarInfo.getOriginPrice())) {
                            Integer curPrice = (int) ((esRoomCalendarInfo.getOriginPrice() * Double.parseDouble(highPercent)) / 100) * 100;
                            Integer bottomPrice = (int) ((esRoomCalendarInfo.getOriginPrice() * Double.parseDouble(lowPercent)) / 100) * 100;
                            esRoomCalendarInfo.setSalePrice(curPrice);
                            esRoomCalendarInfo.setBottomPrice(bottomPrice);
                        }
                    });
                    //执行房态价格更新
                    elasticSearchService.updateMoreRoomCalendar(esRoomCalendarInfos, indexName);
                    log.info("===================房态价格更新成功，当前是第【{}】页，收尾ID为：{} ---- {}==========================",
                            pageNumTmp, esRoomCalendarInfos.get(0).getCalendarId(),
                            esRoomCalendarInfos.get(esRoomCalendarInfos.size() - 1).getCalendarId());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        } while (!CollectionUtils.isEmpty(esRoomCalendarInfos));

        long endTime = System.currentTimeMillis();

        log.info("房态价格全部更新完成，消耗总时长【{}】毫秒",
                (endTime - startTime));
    }

    @Override
    public void updateRoomImageIndexHotel(String indexName, String sourceType, Integer pageSize, Integer pageNo) {

        long startTime = System.currentTimeMillis();
        List<EsRoomInfo> roomInfoList = null;
        //先分页查询所有的cn房间信息
        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                int pageNumTmp = pageNo++;
                roomInfoList = elasticSearchService.esRoomSearch(indexName, sourceType, null, pageSize, pageNumTmp);
                if (!CollectionUtils.isEmpty(roomInfoList)) {
                    roomInfoList.forEach(esRoomInfo -> {
                        //根据房间查询酒店
                        List<EsHotelInfo> hotelInfoList = elasticSearchService.esHotelSearch(indexName, sourceType,
                                EsIndexConstant.ID_PREX_CNBOOKING_HOTEL + esRoomInfo.getHotelId(), 1, 1);
                        if (!CollectionUtils.isEmpty(hotelInfoList)) {
                            EsHotelInfo esHotelInfo = hotelInfoList.get(0);
                            //【设置图片】
                            List<String> picUrls = Lists.newArrayList();
                            randomPicture(picUrls, esHotelInfo);
                            if (!CollectionUtils.isEmpty(picUrls)) {
                                JsonImageRoom roomImages = new JsonImageRoom();
                                roomImages.setImgUrlList(picUrls);
                                esRoomInfo.setExtraInfo(JSON.toJSONString(roomImages));
                            }
                        }
                    });
                }
                //存入新的房间信息
                elasticSearchService.createMoreRoomDocument(roomInfoList, indexName);
                log.info("===================房间图片更新成功，当前是第【{}】页==========================", pageNumTmp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } while (!CollectionUtils.isEmpty(roomInfoList));

        long endTime = System.currentTimeMillis();

        log.info("房态价格全部更新完成，消耗总时长【{}】毫秒",
                (endTime - startTime));

    }

    /**
     * 更新ES酒店图片
     *
     * @param sourceId 酒店资源ID
     * @param imgJson  图片JSON数据
     * @return
     */
    @Override
    public Boolean updateHotelImage(String sourceId, String imgJson) {

        String id = EsIndexConstant.ID_PREX_CNBOOKING_HOTEL + sourceId;
        boolean flag = false;

        List<EsHotelInfo> esHotelInfoList = elasticSearchService.esHotelSearch(EsIndexConstant.INDEX_HOTEL2,
                "cn", id, 10, 1);
        if (!CollectionUtils.isEmpty(esHotelInfoList)) {
            Map<String, String> map = Maps.newHashMap();
            if (!StringUtils.isEmpty(imgJson)) {
                //对应Es中的字段
                map.put("extraInfo", imgJson);
            }

            UpdateResponse updateResponse = elasticSearchService.updateHotelOrRoomImage(id, map, EsIndexConstant.INDEX_HOTEL2);
            if (updateResponse.status().getStatus() == RestStatus.OK.getStatus()) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 更新Es中客房的图片信息
     *
     * @param sourceId 房间资源ID
     * @param imgJson  图片JSON数据
     * @return true 更新成功， false 更新失败
     */
    @Override
    public Boolean updateRoomImage(String sourceId, String imgJson) {
        String id = EsIndexConstant.ID_PREX_CNBOOKING_ROOM + sourceId;
        boolean flag = false;

        List<EsRoomInfo> esRoomInfoList = elasticSearchService.esRoomSearch(EsIndexConstant.INDEX_HOTEL2,
                "cn", id, 10, 1);
        if (!CollectionUtils.isEmpty(esRoomInfoList)) {
            Map<String, String> map = Maps.newHashMap();
            if (!StringUtils.isEmpty(imgJson)) {
                //对应Es中的字段
                map.put("extraInfo", imgJson);
            }

            UpdateResponse updateResponse = elasticSearchService.updateHotelOrRoomImage(id, map, EsIndexConstant.INDEX_HOTEL2);
            if (updateResponse.status().getStatus() == RestStatus.OK.getStatus()) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 定时删除过期数据信息
     *
     * @param indexName 索引名称
     * @param pageSize  页大小
     * @param pageNo    当前页
     * @return
     */
    @Override
    public Boolean delOverTimeCalendarData(String indexName, String sourceType, Integer pageSize, Integer pageNo) {

        long startTime = System.currentTimeMillis();
        List<EsRoomCalendarInfo> esRoomCalendarInfoList = null;
        List<String> indexIds = Lists.newArrayList();
        boolean flag = false;
        String calendarId = null;
        if ("yyks".equals(sourceType)) {
            calendarId = EsIndexConstant.ID_PREX_YYKS_CALENDAR;
        }
        //先分页查询所有的cn房间信息
        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                int pageNumTmp = pageNo++;
                esRoomCalendarInfoList = elasticSearchService.c2bSearchCalendar(
                        indexName, sourceType, calendarId, pageSize, pageNumTmp);
                if (!CollectionUtils.isEmpty(esRoomCalendarInfoList)) {
                    for (EsRoomCalendarInfo calendarInfo : esRoomCalendarInfoList) {
                        //如果大于一天，直接删除
                        if (DateUtils.dateCompareDate(DateUtils.localDateToDate(LocalDate.now()),
                                DateUtils.dayAfter(calendarInfo.getDate(), 1))) {
                            indexIds.add(calendarInfo.getCalendarId());
                        }
                    }
                    BulkResponse bulkItemResponses = elasticSearchService.deleteOverTimeCalendar(indexName, indexIds);
                    if (null != bulkItemResponses && bulkItemResponses.status().getStatus() == RestStatus.OK.getStatus()) {
                        flag = true;
                        //集合清空
                        indexIds.clear();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } while (!CollectionUtils.isEmpty(esRoomCalendarInfoList));

        long endTime = System.currentTimeMillis();

        log.info("过期房态删除完成，消耗总时长【{}】毫秒",
                (endTime - startTime));

        return flag;
    }

    @Override
    public Boolean delRoomByCalendarIsNull(String indexName, String sourceType, Integer pageSize, Integer pageNo) {

        long startTime = System.currentTimeMillis();
        List<EsRoomInfo> esRoomInfoList = null;
        boolean flag = false;
        //先分页查询所有的cn房间信息
        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                int pageNumTmp = pageNo++;
                esRoomInfoList = elasticSearchService.esRoomSearch(indexName, sourceType, null, pageSize, pageNumTmp);
                List<String> deleteIds = Lists.newArrayList();
                if (!CollectionUtils.isEmpty(esRoomInfoList)) {
                    esRoomInfoList.forEach(esRoomInfo -> {
                        List<EsRoomCalendarInfo> esRoomCalendarInfoList = elasticSearchService.queryCalendarByParentId(esRoomInfo.getSourceId(), indexName);
                        if (CollectionUtils.isEmpty(esRoomCalendarInfoList)) {
                            //删除房间
                            deleteIds.add(esRoomInfo.getRoomId());
                        }
                    });
                }

                BulkResponse bulkItemResponses = elasticSearchService.deleteOverTimeCalendar(indexName, deleteIds);
                if (null != bulkItemResponses && bulkItemResponses.status().getStatus() == RestStatus.OK.getStatus()) {
                    log.info("删除的房间有：" + JSON.toJSONString(deleteIds));
                    flag = true;
                    //集合清空
                    deleteIds.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } while (!CollectionUtils.isEmpty(esRoomInfoList));

        long endTime = System.currentTimeMillis();

        log.info("删除无用房间完成，消耗总时长【{}】毫秒",
                (endTime - startTime));

        return flag;
    }

    @Override
    public Boolean delHotelByRoomIsNull(String indexName, String sourceType, Integer pageSize, Integer pageNo) {

        long startTime = System.currentTimeMillis();
        List<EsHotelInfo> esHotelInfoList = null;
        boolean flag = false;
        //先分页查询所有的cn房间信息
        if (null == pageNo) {
            pageNo = 1;
        }
        do {
            try {
                esHotelInfoList = elasticSearchService.esHotelSearch(indexName, indexName, null, pageSize, pageNo);
                List<String> deleteIds = Lists.newArrayList();
                if (!CollectionUtils.isEmpty(esHotelInfoList)) {
                    esHotelInfoList.forEach(esHotelInfo -> {
                        List<EsRoomInfo> esRoomInfoList = elasticSearchService.queryByParentId(esHotelInfo.getSourceId(), indexName);
                        if (CollectionUtils.isEmpty(esRoomInfoList)) {
                            //删除酒店
                            deleteIds.add(esHotelInfo.getHotelId());
                        }
                    });
                }

                BulkResponse bulkItemResponses = elasticSearchService.deleteOverTimeCalendar(indexName, deleteIds);
                if (null != bulkItemResponses && bulkItemResponses.status().getStatus() == RestStatus.OK.getStatus()) {
                    log.info("删除的酒店有：" + JSON.toJSONString(deleteIds));
                    flag = true;
                    //集合清空
                    deleteIds.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } while (!CollectionUtils.isEmpty(esHotelInfoList));

        long endTime = System.currentTimeMillis();

        log.info("删除无用酒店完成，消耗总时长【{}】毫秒",
                (endTime - startTime));

        return flag;
    }

    /**
     * 负责MQ消费是插入信息
     *
     * @param esHotelInfo
     * @param indexName
     */
    @Override
    public void importRoomAndCalendarByHotel(EsHotelInfo esHotelInfo, String roomId,  String indexName) {
        List<EsRoomInfo> roomInfoList = Lists.newArrayList();
        CbHotel cbHotel = new CbHotel();
        cbHotel.setCountryId("0001");
        cbHotel.setCityId(esHotelInfo.getCityId());
        cbHotel.setProvinceId(esHotelInfo.getProvinceId());
        cbHotel.setHotelId(String.valueOf(esHotelInfo.getSourceId()));
        String cityPercent = this.getCityPercent(esHotelInfo.getProvinceId(), esHotelInfo.getCityId());
        double highPercent = EsCnPrice.HIGH_PERCENT;
        double lowPercent = EsCnPrice.LOW_PERCENT;
        if (Arguments.strNotNull(cityPercent)) {
            String[] split = cityPercent.split("-");
            lowPercent = Double.parseDouble(split[0].trim());
            highPercent = Double.parseDouble(split[1].trim());
        }
        //存入房间数据，根据房间ID 查询房间信息
        List<EsRoomInfo> roomListByCnBooking = getRoomListByCnBooking( cbHotel, esHotelInfo, lowPercent, highPercent );
        if(!CollectionUtils.isEmpty( roomListByCnBooking )){
            for(EsRoomInfo nowRoom : roomListByCnBooking){
                if(Objects.equals( nowRoom.getSourceId(), roomId)){
                    roomInfoList.add(nowRoom);
                }
            }
        }
        if (!CollectionUtils.isEmpty(roomInfoList)) {
            //存入房态信息
            getRoomCalendarByHotelAndRoomId(indexName,
                    roomInfoList.get(0),
                    cbHotel.getCountryId(),
                    esHotelInfo.getProvinceId(),
                    esHotelInfo.getCityId(),
                    lowPercent,
                    highPercent);
        }
    }

    @Override
    public int importHotelByCreateTimeGtCityId(String indexName, Integer pageNo, Integer pageSize, Integer id) {

        List<ImportCityDataConfig> list = importCityDataConfigService.list(new QueryWrapper<ImportCityDataConfig>()
        .ge(ImportCityDataConfig.ID, id));
        if(!CollectionUtils.isEmpty(list)){
            for (ImportCityDataConfig importCityDataConfig : list){
                //执行数据导入
                this.importCnBookingHotelByPage(indexName,"0001",
                        importCityDataConfig.getProvinceId(), importCityDataConfig.getCityId(),
                        pageSize,pageNo);

                log.info(importCityDataConfig.getProvinceName()+"的：" + importCityDataConfig.getCityName() + "导入成功！");
            }
            return 0;
        }
        return -1;
    }


    /**
     * 随机图片的算法
     *
     * @param picUrls
     * @param esHotelInfo
     */
    private void randomPicture(List<String> picUrls, EsHotelInfo esHotelInfo) {

        String extraInfo = esHotelInfo.getExtraInfo();
        if (!StringUtils.isEmpty(extraInfo)) {
            List<String> imgUrlList = JsonUtils.jsonToList(JsonUtils.getJsonToStr("imgUrlList", extraInfo), String.class);
            //截取中3张
            //随机3张，
            if (!CollectionUtils.isEmpty(imgUrlList)) {
                if (imgUrlList.size() >= 5) {
                    //最后5张图的随机3个
                    List<String> randomList = Lists.newArrayList();
                    for (int i = imgUrlList.size(); i > 0; i--) {
                        randomList.add(imgUrlList.get(i - 1));
                        if (randomList.size() == 5) {
                            break;
                        }
                    }
                    List<Integer> random1 = CommonRandomUtils.random(randomList.size(), 3);
                    for (Integer index : random1) {
                        picUrls.add(randomList.get(index));
                    }
                } else if (imgUrlList.size() >= 3) {
                    //五个图片的随机3个
                    List<Integer> random1 = CommonRandomUtils.random(imgUrlList.size(), 3);
                    for (Integer index : random1) {
                        picUrls.add(imgUrlList.get(index));
                    }
                } else {
                    if (imgUrlList.size() > 0) {
                        //直接添加，顺序随机
                        List<Integer> random1 = CommonRandomUtils.random(imgUrlList.size(), imgUrlList.size());
                        for (Integer index : random1) {
                            picUrls.add(imgUrlList.get(index));
                        }
                    }
                }
            }
        }
    }

    /**
     * 拼接CnBooking的【酒店】数据信息（批量）
     */
    private List<EsHotelInfo> getHotelListByCnBooking(CbHotelListSearchParam param) {

        List<EsHotelInfo> esHotelInfoList = Lists.newArrayList();
        List<HotelInfoDTO> hotelInfoDTOList = transitionService.hotelListSearch(param);
        EsHotelInfo esHotelInfo = null;
        if (!CollectionUtils.isEmpty(hotelInfoDTOList)) {
            for (HotelInfoDTO hotelInfoDTO : hotelInfoDTOList) {
                esHotelInfo = convertDTOToEs(hotelInfoDTO);
                if (null != esHotelInfo) {
                    esHotelInfoList.add(esHotelInfo);
                }
            }
        }
        return esHotelInfoList;
    }

    /**
     * 拼接CnBooking的【酒店】数据信息（单条）
     *
     * @param cbHotel 查询酒店参数
     * @return 返回酒店数据
     */
    private EsHotelInfo getHotelByCnBooking(CbHotel cbHotel) {

        HotelInfoDTO hotelInfoDTO = transitionService.hotelSearch(cbHotel.getCountryId(), cbHotel.getHotelId());
        EsHotelInfo esHotelInfo = null;
        if (null != hotelInfoDTO) {
            esHotelInfo = convertDTOToEs(hotelInfoDTO);
        }
        return esHotelInfo;
    }

    /**
     * DTO 转换为 ES
     *
     * @param hotelInfoDTO CNbooking的DTO
     * @return 返回ES_INFO
     */
    private EsHotelInfo convertDTOToEs(HotelInfoDTO hotelInfoDTO) {

        EsHotelInfo esHotelInfo = new EsHotelInfo();
        //验证酒店是否加入黑名单
        if (null != hotelInfoDTO) {
            HotelBlackList one = hotelBlackListMapper.selectOne(new QueryWrapper<HotelBlackList>()
                    .eq(HotelBlackList.SOURCE_ID, hotelInfoDTO.getHotelId())
                    .eq(HotelBlackList.SOURCE_TYPE, "cn")
                    .eq(HotelBlackList.STATUS, 1));
            if (null != one) {
                log.info("===酒店SOURCE_ID为{}的数据已经加入黑名单，已过滤===", hotelInfoDTO.getHotelId());
                return null;
            }
            esHotelInfo = MyBeanUtils.convert(hotelInfoDTO, EsHotelInfo.class);
            //星级
            if (!StringUtils.isEmpty(hotelInfoDTO.getStarLevel())) {
                esHotelInfo.setStarLevel(Integer.valueOf(hotelInfoDTO.getStarLevel()));
            }
            esHotelInfo.setId(Integer.valueOf(hotelInfoDTO.getHotelId()));
            //唯一酒店ID
            esHotelInfo.setHotelId(EsIndexConstant.ID_PREX_CNBOOKING_HOTEL + hotelInfoDTO.getHotelId());
            EsDocType docType = new EsDocType();
            docType.setName(EsIndexConstant.JOIN_TYPE_HOTEL);
            esHotelInfo.setDocType(docType);
            esHotelInfo.setSourceType("cn");
            EsGeoPoint point = new EsGeoPoint();
            if (!StringUtils.isEmpty(hotelInfoDTO.getPositionY()) && !StringUtils.isEmpty(hotelInfoDTO.getPositionX())) {
                point.setLat(Double.parseDouble(hotelInfoDTO.getPositionY()));
                point.setLon(Double.parseDouble(hotelInfoDTO.getPositionX()));
                esHotelInfo.setPositionX(Double.parseDouble(hotelInfoDTO.getPositionX()));
                esHotelInfo.setPositionY(Double.parseDouble(hotelInfoDTO.getPositionY()));
            }
            //坐标位置
            esHotelInfo.setLocation(point);
            esHotelInfo.setSourceId(String.valueOf(hotelInfoDTO.getHotelId()));
            //酒店服务
            esHotelInfo.setServices(JSON.toJSONString(hotelInfoDTO.getServices()));
        }


        return esHotelInfo;
    }

    /**
     * 拼接CnBooking的【房间】数据信息
     *
     * @param cbHotel 查询酒店房间参数
     * @return 返回房间集合
     */
    private List<EsRoomInfo> getRoomListByCnBooking(CbHotel cbHotel, EsHotelInfo esHotelInfo,
                                                    Double lowPercent, Double highPercent) {

        List<EsRoomInfo> roomInfoList = Lists.newArrayList();
        List<RoomInfoDTO> roomInfoDTOList = transitionService.roomSearch(cbHotel.getCountryId(),
                cbHotel.getProvinceId(),
                cbHotel.getCityId(),
                cbHotel.getHotelId(), lowPercent, highPercent);
        if (!CollectionUtils.isEmpty(roomInfoDTOList)) {
            roomInfoList = MyBeanUtils.convertArrayList(roomInfoDTOList, EsRoomInfo.class);
            List<String> picUrls = null;
            for (EsRoomInfo esRoomInfo : roomInfoList) {
                esRoomInfo.setRoomId(EsIndexConstant.ID_PREX_CNBOOKING_ROOM + esRoomInfo.getId());
                EsDocType docType = new EsDocType();
                docType.setName(EsIndexConstant.JOIN_TYPE_ROOM);
                docType.setParent(EsIndexConstant.ID_PREX_CNBOOKING_HOTEL + cbHotel.getHotelId());
                esRoomInfo.setDocType(docType);
                esRoomInfo.setSourceType("cn");
                esRoomInfo.setSourceId(String.valueOf(esRoomInfo.getId()));
                esRoomInfo.setHotelId(Integer.valueOf(cbHotel.getHotelId()));
                //转换图片，如果小于3张则取1张或2张 【来源于esHotelInfo】
                if (StringUtils.isEmpty(esRoomInfo.getExtraInfo())) {
                    //【设置图片】
                    picUrls = Lists.newArrayList();
                    randomPicture(picUrls, esHotelInfo);
                    if (!CollectionUtils.isEmpty(picUrls)) {
                        JsonImageRoom roomImages = new JsonImageRoom();
                        roomImages.setImgUrlList(picUrls);
                        esRoomInfo.setExtraInfo(JSON.toJSONString(roomImages));
                    }
                }
            }

        }
        return roomInfoList;
    }

    /**
     * 拼接CnBooking的【房态】数据信息
     *
     * @param roomInfoList 房间集合信息
     * @param cbHotel      酒店房间查询参数
     * @return 返回房态信息
     */
    private void getRoomCalendarByCnBooking(EsHotelInfo esHotelInfo, String indexName,
                                            List<EsRoomInfo> roomInfoList, CbHotel cbHotel,
                                            Double lowPercent, Double highPercent) {
        List<EsRoomCalendarInfo> roomCalendarInfoList = Lists.newArrayList();
        List<EsRoomCalendarInfo> roomCalendarOneRoom = null;
        List<String> removeRoomSourceIds = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(roomInfoList)) {
            //将价格小于
            //查询本酒店个月的房态信息（7天）
            String checkIn = DateUtils.toYYMMddStr(new Date());
            String checkOut = DateUtils.toYYMMddStr(DateUtils.dayAfter(new Date(), 30));
            //注意，对方的房态是 一个房间，有几种价格计划,我们选取的其中一个计划进行添加(KEY --> roomId value--> 房态集合 )
            Map<String, List<RoomCalendarDTO>> mapRoomCalendarSearch = transitionService.mapRoomCalendarSearch(cbHotel.getCountryId(),
                    cbHotel.getProvinceId(),
                    cbHotel.getCityId(),
                    cbHotel.getHotelId(),
                    null,
                    checkIn, checkOut, lowPercent, highPercent);

            if (!CollectionUtils.isEmpty(mapRoomCalendarSearch)) {
                for (EsRoomInfo esRoomInfo : roomInfoList) {
                    List<RoomCalendarDTO> roomCalendarDTOS = mapRoomCalendarSearch.get(esRoomInfo.getSourceId());
                    if (!CollectionUtils.isEmpty(roomCalendarDTOS)) {
                        roomCalendarOneRoom = MyBeanUtils.convertArrayList(roomCalendarDTOS, EsRoomCalendarInfo.class);
                        for (EsRoomCalendarInfo roomCalendarInfo : roomCalendarOneRoom) {
                            //【rateId和日期】组成房态的唯一键
                            roomCalendarInfo.setCalendarId(EsIndexConstant.ID_PREX_CNBOOKING_CALENDAR + roomCalendarInfo.getId() +
                                    DateUtils.toYYMMddStr(roomCalendarInfo.getDate()));
                            EsDocType docType = new EsDocType();
                            docType.setName(EsIndexConstant.JOIN_TYPE_CALENDAR);
                            docType.setParent(EsIndexConstant.ID_PREX_CNBOOKING_ROOM + roomCalendarInfo.getRoomId());
                            roomCalendarInfo.setDocType(docType);
                            roomCalendarInfo.setSourceType("cn");
                            roomCalendarInfo.setSourceId(String.valueOf(roomCalendarInfo.getId()));
                            roomCalendarInfo.setRoomId(roomCalendarInfo.getRoomId());
                            roomCalendarInfo.setHotelId(Integer.valueOf(cbHotel.getHotelId()));
                        }
                        roomCalendarInfoList.addAll(roomCalendarOneRoom);
                        CnRoomImageMongoEntity cnRoomImageMongoEntity = roomImageMongoMongoService.get(esRoomInfo.getSourceId());
                        if (null != cnRoomImageMongoEntity) {
                            esRoomInfo.setExtraInfo(cnRoomImageMongoEntity.getImages());
                        }

                    } else {
                        //如果map中找不到这个房间，就直接删除没有房态的房间
                        removeRoomSourceIds.add(esRoomInfo.getSourceId());
                    }
                }
            }
            //移除room中没有房态的数据（用迭代器移除）
            if (!CollectionUtils.isEmpty(removeRoomSourceIds)) {
                roomInfoList.removeIf(esRoomInfo -> removeRoomSourceIds.contains(esRoomInfo.getSourceId()));
            }

        }
        //存储
        if (!CollectionUtils.isEmpty(roomCalendarInfoList)) {
            //酒店
            CnHotelImageMongoEntity cnHotelImageMongoEntity = hotelImageMongoMongoService.get(esHotelInfo.getSourceId());
            if (null != cnHotelImageMongoEntity) {
                esHotelInfo.setExtraInfo(cnHotelImageMongoEntity.getImages());
            }
            elasticSearchService.createHotelDocument(JSONUtil.toJsonStr(esHotelInfo), indexName, esHotelInfo.getHotelId());
            //房间
            elasticSearchService.createMoreRoomDocument(roomInfoList, indexName);
            //房态
            elasticSearchService.createMoreRoomCalendarDocument(roomCalendarInfoList, indexName);
            log.info("来源于CnBooking， 酒店ID为 【{}】的数据完成录入", esHotelInfo.getId());
        }
    }

    /**
     * 得到该城市的上下浮动的比例，在进行录入
     *
     * @param provinceId 省份Id
     * @param cityId     城市Id
     * @return
     */
    private String getCityPercent(String provinceId, String cityId) {
        String redisKey = BuilderKey.build(RedisKey.CITY_PERCENT_PRICE, provinceId + ":" + cityId);
        String redisValue = redisService.get(redisKey);
        if (Arguments.strNotNull(redisKey)) {
            return redisValue;
        }
        return null;
    }

    /**
     * 只添加房间房态信息
     * @param indexName 索引名称
     * @param esRoomInfo 导入最新房间对象
     * @param countryId 国家ID
     * @param provinceId 省份ID
     * @param cityId 城市
     * @param lowPercent 最低百分比
     * @param highPercent 最高百分比
     */
    private void getRoomCalendarByHotelAndRoomId(String indexName,
                                            EsRoomInfo esRoomInfo,
                                            String countryId,
                                            String provinceId,
                                            String cityId,
                                            Double lowPercent,
                                            Double highPercent) {
        List<EsRoomCalendarInfo> roomCalendarInfoList = Lists.newArrayList();
        List<EsRoomCalendarInfo> roomCalendarOneRoom;
        if (null != esRoomInfo) {
            //查询本酒店个月的房态信息（15天）
            String checkIn = DateUtils.toYYMMddStr(new Date());
            String checkOut = DateUtils.toYYMMddStr(DateUtils.dayAfter(new Date(), 15));
            //注意，对方的房态是 一个房间，有几种价格计划,我们选取的其中一个计划进行添加(KEY --> roomId value--> 房态集合 )
            Map<String, List<RoomCalendarDTO>> mapRoomCalendarSearch = transitionService.mapRoomCalendarSearch(countryId,
                    provinceId,
                    cityId,
                    String.valueOf( esRoomInfo.getHotelId()),
                    esRoomInfo.getSourceId(),
                    checkIn, checkOut, lowPercent, highPercent);
            if (!CollectionUtils.isEmpty(mapRoomCalendarSearch)) {
                List<RoomCalendarDTO> roomCalendarDTOS = mapRoomCalendarSearch.get(esRoomInfo.getSourceId());
                if (!CollectionUtils.isEmpty(roomCalendarDTOS)) {
                    roomCalendarOneRoom = MyBeanUtils.convertArrayList(roomCalendarDTOS, EsRoomCalendarInfo.class);
                    for (EsRoomCalendarInfo roomCalendarInfo : roomCalendarOneRoom) {
                        //【rateId和日期】组成房态的唯一键
                        roomCalendarInfo.setCalendarId(
                                (EsIndexConstant.ID_PREX_CNBOOKING_CALENDAR +
                                        roomCalendarInfo.getId() +
                                        DateUtils.toYYMMddStr(roomCalendarInfo.getDate())).trim());
                        EsDocType docType = new EsDocType();
                        docType.setName(EsIndexConstant.JOIN_TYPE_CALENDAR);
                        docType.setParent(EsIndexConstant.ID_PREX_CNBOOKING_ROOM + roomCalendarInfo.getRoomId());
                        roomCalendarInfo.setDocType(docType);
                        roomCalendarInfo.setSourceType("cn");
                        roomCalendarInfo.setSourceId(String.valueOf(roomCalendarInfo.getId()));
                        roomCalendarInfo.setRoomId(roomCalendarInfo.getRoomId());
                        roomCalendarInfo.setHotelId(esRoomInfo.getHotelId());
                    }
                    roomCalendarInfoList.addAll(roomCalendarOneRoom);
                    CnRoomImageMongoEntity cnRoomImageMongoEntity = roomImageMongoMongoService.get(esRoomInfo.getSourceId());
                    if (null != cnRoomImageMongoEntity) {
                        esRoomInfo.setExtraInfo(cnRoomImageMongoEntity.getImages());
                    }
                }
            }
            //存储
            if (!CollectionUtils.isEmpty(roomCalendarInfoList)) {
                //房间
                elasticSearchService.createMoreRoomDocument( Collections.singletonList( esRoomInfo ), indexName);
                //房态
                elasticSearchService.createMoreRoomCalendarDocument(roomCalendarInfoList, indexName);
                log.info("房态同步成功！当前线程【{}】, 房间ID【{}】, 酒店ID 【{}】",
                        Thread.currentThread().getName(),esRoomInfo.getSourceId(), esRoomInfo.getHotelId());
            }
        }
    }
}
